package top.hg.tool.modules.car.index;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.hg.tool.common.exception.CarException;
import top.hg.tool.modules.car.constant.CarConstant;
import top.hg.tool.modules.car.constant.RedisKeyConstant;
import top.hg.tool.modules.car.person.LotteryPersonEntity;
import top.hg.tool.modules.car.person.LotteryPersonRepository;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * created by skh on 2019/7/13
 */
@Slf4j
@Service
public class IndexService extends ServiceImpl<IndexDao, IndexEntity> {

	@Autowired
	private LotteryPersonRepository lotteryPersonRepository;

	@Autowired
	private IndexRepository indexRepository;

	@Autowired
	private StringRedisTemplate redisTemplate;

	public static void main(String[] args) {
		IndexService indexService = new IndexService();
		String fileName = "8号摇号指标";
		String issue = "201908";
		String splitStr = "      ";
		String pdfPath = "C:\\Users\\kaihu\\Desktop\\code\\MyCode\\hg-tool\\src\\main\\resources\\pdf\\" + fileName + ".pdf";
		String targetPath = "C:\\Users\\kaihu\\Desktop\\code\\MyCode\\hg-tool\\src\\main\\resources\\pdf\\" + fileName + ".txt";
		String sqlPath = "C:\\Users\\kaihu\\Desktop\\code\\MyCode\\hg-tool\\src\\main\\resources\\pdf\\" + fileName + ".sql";
		//indexService.parsePdf(pdfPath, targetPath);

		indexService.saveIndexToSqlFile(targetPath, issue, sqlPath, splitStr);
	}

	//解析pdf
	public void parsePdf(String pdfPath, String targetPath) {
		try {
			// 是否排序
			boolean sort = false;
			// 开始提取页数
			int startPage = 1;
			// 结束提取页数
			int endPage = Integer.MAX_VALUE;
			String content = null;
			PrintWriter writer = null;
			//todo pdf文本路径
			String path = pdfPath;
			//todo 输出txt文本路径
			String target = targetPath;
			PDDocument document = PDDocument.load(new File(path));
			PDFTextStripper pts = new PDFTextStripper();
			endPage = document.getNumberOfPages();
			log.info("Total Page: " + endPage);
			pts.setStartPage(startPage);
			pts.setEndPage(endPage);
			try {
				//content就是从pdf中解析出来的文本
				content = pts.getText(document);
				writer = new PrintWriter(new FileOutputStream(target));
				writer.write(content);// 写入文件内容
				writer.flush();
				writer.close();
			} catch (Exception e) {
				throw e;
			} finally {
				if (null != document) {
					document.close();
				}
			}
			log.info("Get PDF Content Success...");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//解析txt
    /*
    1.首先需要操作txt文件.去掉无用信息,将首行顶头
    2.根据空格分隔数据,因为是等间距的空格
    3.正确的结果是 无效数量就是页数, 有效数量就是编号的最大值.
     */
	public List<IndexEntity> parseTxt(String targetPath, String issue, String splitStr) {
		if (StrUtil.isBlank(issue)) {
			throw new CarException("期号不能为空");
		}
		//todo 修改文件路径
		File file = new File(targetPath);
		List<String> result = new ArrayList<>();
		result = FileUtil.readLines(file, "UTF-8", result);
		int count = 0; //无效数量
		int validCount = 0; //有效数量
		List<IndexEntity> indexEntityList = new ArrayList<>();

		for (String index : result) {
			//todo 需要修改空格的值
			String[] split = StrUtil.split(index, splitStr);
			if (split.length != 3) {
				//说明是页数
				count++;
				continue;
			} else {
				validCount++;
				IndexEntity indexEntity = new IndexEntity();
				indexEntity.setApplyNum(StrUtil.trim(split[1]));
				indexEntity.setName(StrUtil.trim(split[2]));
				indexEntity.setIssue(issue); //todo 注意每期记得修改这个参数
				indexEntity.setCreateTime(new Date());
				indexEntityList.add(indexEntity);
			}
		}
		log.info("解析完成,总行数:{},无效数量:{},有效数量:{}", result.size(), count, validCount);
		log.info("过滤后集合数量:{},解析后数据为:{},{}", indexEntityList.size(), indexEntityList.get(0), indexEntityList.get(indexEntityList.size() - 1));
		return indexEntityList;
	}


	public void saveIndexToSqlFile(String targetPath, String issue, String sqlPath, String splitStr) {
		//解析数据
		List<IndexEntity> indexEntityList = this.parseTxt(targetPath, issue, splitStr);
		List<String> formatList = new ArrayList<>();
		for (IndexEntity indexEntity : indexEntityList) {
			String sql = "INSERT INTO `hg_tool`.`tb_index`(`apply_num`, `name`, `issue`, `create_time`) VALUES ('{}', '{}', '{}', '{}');";
			String format = StrUtil.format(sql, indexEntity.getApplyNum(), indexEntity.getName(), indexEntity.getIssue(), DateUtil.formatDateTime(indexEntity.getCreateTime()));
			formatList.add(format);
		}
		log.info("sql:{}", formatList.get(0));
		log.info("sql:{}", formatList.get(formatList.size() - 1));
		//todo 修改文件名
		String path = sqlPath;
		File file = FileUtil.file(path);
		FileUtil.writeLines(formatList, file, "UTF-8");
		log.info("生成新增数据完成");
	}


	public List<IndexEntity> queryIndex(String query) {
		query = StrUtil.trim(query);
		if (StrUtil.isBlank(query)) {
			throw new CarException("查询条件不能为空");
		}

		if (query.length() > 20) {
			throw new CarException("查询条件过长,请输入合法查询条件");
		}

		//判断是否是数字,如果不是数字,则按名称搜索
		if (NumberUtil.isInteger(query)) {
			if (query.length() != 13) {
				throw new CarException("请输入13位合法的摇号编号");
			}
			return indexRepository.selectIndexByApplyNum(query);

		} else {
			return indexRepository.selectIndexByName(query);
		}
	}


	@Transactional
	public List<LotteryPersonEntity> batchQueryIndex(String openId) {

		//从缓存里查,如果有,则直接返回,没有,则去查一次.
		try {
			String personList = redisTemplate.opsForValue().get(RedisKeyConstant.car_person_list_openId + openId);
			if (StrUtil.isNotBlank(personList)) {
				log.debug("get personList from cache");
				return JSONUtil.toList(JSONUtil.parseArray(personList), LotteryPersonEntity.class);
			}
		} catch (Exception e) {
			log.error("获取缓存异常:[{}]", e.getMessage(), e);
		}

		log.debug("get personList from db");
		//查询该用户下所有摇号人员
		List<LotteryPersonEntity> lotteryPersonList = lotteryPersonRepository.getPersonListByOpenId(openId);
		if (CollUtil.isEmpty(lotteryPersonList)) {
			throw new CarException("请先新增摇号人");
		}

		for (LotteryPersonEntity lotteryPersonEntity : lotteryPersonList) {
			List<IndexEntity> indexEntities = indexRepository.selectIndexByApplyNum(lotteryPersonEntity.getApplyNum());
			log.info("一键批量查询,姓名:[{}],编号:[{}]", lotteryPersonEntity.getName(), lotteryPersonEntity.getApplyNum());
			updatePersonIndexStatusByResult(lotteryPersonEntity, indexEntities);
		}

		//设置缓存
		try {
			redisTemplate.opsForValue().set(RedisKeyConstant.car_person_list_openId + openId, JSONUtil.toJsonStr(lotteryPersonList), 1, TimeUnit.DAYS);
			log.debug("set personList to cache");
		} catch (Exception e) {
			log.error("设置缓存异常:[{}]", e.getMessage(), e);
		}

		return lotteryPersonList;
	}

	public List<IndexEntity> queryIndexByPersonId(Integer personId) {
		LotteryPersonEntity lotteryPersonEntity = lotteryPersonRepository.getPersonById(personId);
		String applyNum = lotteryPersonEntity.getApplyNum();
		List<IndexEntity> indexEntities = indexRepository.selectIndexByApplyNum(applyNum);
		log.info("查询指定人员的个人指标,姓名:[{}],编号:[{}]", lotteryPersonEntity.getName(), applyNum);
		updatePersonIndexStatusByResult(lotteryPersonEntity, indexEntities);
		return indexEntities;
	}

	private void updatePersonIndexStatusByResult(LotteryPersonEntity lotteryPersonEntity, List<IndexEntity> indexEntities) {
		if (CollUtil.isEmpty(indexEntities)) {
			lotteryPersonEntity.setStatus(CarConstant.hit_fail);
			lotteryPersonEntity.setIssue("");
			lotteryPersonRepository.updatePersonById(lotteryPersonEntity);
		} else {
			IndexEntity indexEntity = indexEntities.get(0);
			lotteryPersonEntity.setStatus(CarConstant.hit_success);
			lotteryPersonEntity.setIssue(indexEntity.getIssue());
			lotteryPersonRepository.updatePersonById(lotteryPersonEntity);
		}
	}
}
